#include "sk6812_spi.h"

// 灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24] = {0};
// 灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {

    // R    G      B
    0XFF, 0X00, 0X00, // 0
    0X00, 0XC0, 0X00, // 1
    0X00, 0X00, 0X80, // 2
     0X15, 0X15, 0X15
};
//将指定LED的RGB颜色值转换为WS2812B协议要求的SPI数据格式，并存储到SPI发送缓冲区中。
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t *pR = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 8]; // 设置单个不同颜色分量的起始位置。Ws2b812b_NUM是第0颗。
    uint8_t *pG = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24];
    uint8_t *pB = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 16];

    for (uint8_t i = 0; i < 8; i++)
    {
        if (g & 0x80)
        {
            *pG = CODE_1;
        }
        else
        {
            *pG = CODE_0;
        }
        if (r & 0x80)
        {
            *pR = CODE_1;
        }
        else
        {
            *pR = CODE_0;
        }
        if (b & 0x80)
        {
            *pB = CODE_1;
        }
        else
        {
            *pB = CODE_0;
        }
        r <<= 1;
        g <<= 1;
        b <<= 1;
        pR++;
        pG++;
        pB++;
    }
}
//更新函数 ，负责将内存中的颜色数据实际发送到LED硬件上显示。 
void WS2812B_Task(void)
{
    // 将gWs2812bDat数据解析成SPI数据
    for (uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
    {
        WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
    }
    // 总线输出数据
    HAL_SPI_Transmit(&Spi1Handle, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), 0XFFFF);
    uint8_t dat = 0;
    // 使总线输出低电平
    HAL_SPI_Transmit(&Spi1Handle, &dat, 1, 0XFFFF);
    // 帧信号：一个大于50us的低电平
    HAL_Delay(1);
}

// Red to Green Stack效果：红色LED从顶部掉落，落下瞬间变绿色并累积
void WS2812B_red_to_green_stack(void)
{
    static uint8_t stack_step = 0;        // 记录当前 LED 的掉落步骤（控制红色 LED 从顶部向下移动的进度）
    static uint8_t green_count = 0;       // 记录已堆叠变绿的 LED 数量

    // 清除所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }
    
    // 显示已经落下并变绿的LED（从底部开始累积）首先是不显示绿色
    for (uint8_t i = 0; i < green_count; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 255;  // 绿色
        gWs2812bDat[i].B = 0;
    }
    
    // 进入掉落阶段
    if (green_count < WS2812B_AMOUNT)
    {
        // 计算红色灯珠掉落的位置（从顶部掉落到绿色堆积的顶部），LED29
        uint8_t falling_pos = WS2812B_AMOUNT - 1 - stack_step;
        
        // 如果掉落位置还在绿色堆积之上，显示红色掉落LED
        if (falling_pos >= green_count) // 设置 LED29 为红色（顶部红色 LED 开始掉落）。
        {
            gWs2812bDat[falling_pos].R = 255;  // 掉落中的红色LED
            gWs2812bDat[falling_pos].G = 0;
            gWs2812bDat[falling_pos].B = 0;
        }
        
        stack_step++;
        
        // 当红色LED落到绿色堆积顶部时，变成绿色并增加绿色计数
        /*判断是否落地：stack_step (1) > 29？否，不更新green_count。
        如果29次掉落，判断是否落地：stack_step (29) > 29 - green_count（29）？是，更新green_count。
        */
        if (stack_step > (WS2812B_AMOUNT - 1 - green_count))
        {
            green_count++;  // 增加绿色LED数量
            stack_step = 0; // 重置掉落步骤，准备下一个LED掉落
        }
    }
    else
    {
        // 所有LED都变绿后，重新开始循环
        green_count = 0;
        stack_step = 0;
    }
    
    // 发送数据到LED硬件
    WS2812B_Task();
}
